package com.motong.gongdan.service;

import cn.hutool.json.JSONUtil;
import com.alibaba.excel.util.IoUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.motong.gongdan.entity.*;
import com.motong.gongdan.enums.ObjectType;
import com.motong.gongdan.mapper.ProductMapper;
import com.motong.gongdan.util.*;
import com.motong.gongdan.vo.H5Vo.H5CodeVo;
import com.motong.gongdan.vo.H5Vo.common.GroupCountVo;
import com.motong.gongdan.vo.H5Vo.customfield.RadioOptionVo;
import com.motong.gongdan.vo.system.CustomField.ColumnsConfigure;
import com.motong.gongdan.vo.system.CustomField.ColumnsConfigureList;
import com.motong.gongdan.vo.system.otherVo.CustomFieldVo;
import com.motong.gongdan.vo.system.stock.vo.StockBalanceVo;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author:fff
 * @time:2022/2/23
 */
@Service
public class ProductService extends ServiceImpl<ProductMapper, Product> {
    @Resource
    CustomFieldService customFieldService;
    @Resource
    ProductService productService;
    @Resource
    ProcessRouteService processRouteService;
    @Resource
    CustomNumberService customNumberService;
    @Resource
    UnitService unitService;
    @Resource
    UserService userService;
    @Resource
    private ProductMapper productMapper;
    @Resource
    private WorkReportService workReportService;
    @Resource
    private MissionService missionService;
    @Resource
    private StockMsgService stockMsgService;
    @Resource
    private ScreenPlanService screenPlanService;

    public void handleImport(MultipartFile file, Integer type) throws IOException {
        byte[] stream = IoUtils.toByteArray(file.getInputStream());
        List<Map<String, String>> allDataList = EasyExcelImportUtils.parseExcelToData(stream, 2);

        // 空值导入日志
        userService.importBlankExcel(allDataList, "product");

        List<ColumnsConfigureList> allList = userService.handleDefault();
        Map<String, Integer> dataMap = new HashMap<>();
        List<Map<String, String>> failList = new ArrayList<>();
        int a = 0;
        int b = 0;
        List<ColumnsConfigure> defaultColumns = customFieldService.handleImportDefault("product");
        if (allList.stream().filter(f -> f.getType().equals("product")).findAny().orElse(null) != null) {
            List<ColumnsConfigure> list = allList.stream().filter(f -> f.getType().equals("product")).findAny().orElse(null).getColumns();
            for (Map<String, String> s : allDataList) {
                Map<String, String> failMap = new HashMap<>();
                Product p = new Product();
                List<CustomFieldVo> vos = new ArrayList<>();
                //表头
                List<String> keyList = new ArrayList<>(s.keySet());
                if (!defaultColumns.stream().filter(f -> f.getChineseName().equals(keyList.get(0))).findAny().isPresent()) {
                    failMap.put("失败原因", "模版读取错误");
                    failList.add(failMap);
                    b++;
                    break;
                }
                int flag = 0;
                for (int i = 0; i < keyList.size() && flag == 0; i++) {
                    if (i >= list.size()) {
                        if (StringUtil.isNotBlank(keyList.get(i)) && StringUtil.isNotBlank(s.get(keyList.get(i)))) {
                            CustomField cf = customFieldService.getOne(new QueryWrapper<CustomField>().eq("field_ascription", "product").eq("chinese_name", keyList.get(i)));
                            CustomFieldVo vo = new CustomFieldVo();
                            vo.setCustomFieldId(cf.getId());
                            vo.setValue(s.get(keyList.get(i)));
                            vos.add(vo);
                        }
                    } else {
                        switch (i) {
                            case 0:
                                if (StringUtil.isNotBlank(s.get(keyList.get(i)))) {
                                    Product old = productService.getOne(new QueryWrapper<Product>().eq("code", s.get(keyList.get(i))));
                                    if (old == null) {
                                        p.setCode(s.get(keyList.get(i)));
                                    } else if (old != null && type == 1) {
                                        p = old;
                                    } else {
                                        String code = customNumberService.generator(7);
                                        if (code.equals("fail")) {
                                            failMap.put("失败原因", "流水号已使用完");
                                            failMap.put("产品编号", s.get(keyList.get(i)));
                                            failMap.put("产品名称", s.get(keyList.get(i + 1)));
                                            failMap.put("产品规格", s.get(keyList.get(i + 2)));
                                            failMap.put("单位", s.get(keyList.get(i + 3)));
                                            failList.add(failMap);
                                            b++;
                                            flag = 1;
                                            break;
                                        }
                                        p.setCode(code);
//                                        failMap.put("失败原因","已存在相同编号产品");
//                                        failMap.put("产品编号",s.get(keyList.get(i)));
//                                        failMap.put("产品名称",s.get(keyList.get(i+1)));
//                                        failMap.put("产品规格",s.get(keyList.get(i+2)));
//                                        failMap.put("单位",s.get(keyList.get(i+3)));
//                                        failList.add(failMap);
//                                        b++;
//                                        flag=1;
//                                        break;
                                    }
                                } else {
                                    String code = customNumberService.generator(7);
                                    if (code.equals("fail")) {
                                        failMap.put("失败原因", "流水号已使用完");
                                        failMap.put("产品编号", s.get(keyList.get(i)));
                                        failMap.put("产品名称", s.get(keyList.get(i + 1)));
                                        failMap.put("产品规格", s.get(keyList.get(i + 2)));
                                        failMap.put("单位", s.get(keyList.get(i + 3)));
                                        failList.add(failMap);
                                        b++;
                                        flag = 1;
                                        break;
                                    }
                                    p.setCode(code);
                                }
                                continue;
                            case 1:
                                if (StringUtil.isBlank(s.get(keyList.get(i)))) {
                                    failMap.put("失败原因", "产品名称不能为空");
                                    failList.add(failMap);
                                    b++;
                                    flag = 1;
                                    break;
                                } else {
                                    p.setName(s.get(keyList.get(i)));
                                }
                                continue;
                            case 2:
                                p.setSpecification(StringUtil.isNotBlank(s.get(keyList.get(i))) ? s.get(keyList.get(i)) : "");
                                continue;
                            case 3:
                                if (StringUtil.isBlank(s.get(keyList.get(i)))) {
                                    failMap.put("失败原因", "产品单位不能为空");
                                    failList.add(failMap);
                                    b++;
                                    flag = 1;
                                    break;
                                } else {
                                    Unit unit = unitService.getOne(new QueryWrapper<Unit>().eq("name", s.get(keyList.get(i))));
                                    if (unit == null) {
                                        failMap.put("失败原因", "产品单位不存在");
                                        failList.add(failMap);
                                        b++;
                                        flag = 1;
                                        break;
                                    } else {
                                        p.setUnitId(unit.getId());
                                    }
                                }
                                continue;
                            case 4:
                                if (StringUtil.isNotBlank(s.get(keyList.get(i)))) {
                                    ProcessRoute processRoute = processRouteService.getOne(new QueryWrapper<ProcessRoute>().eq("code", s.get(keyList.get(i))));
                                    if (Objects.nonNull(processRoute)) {
                                        p.setProcessRouteId(processRoute.getId());
                                    }
                                }
                                continue;
                            case 5:
                                if (StringUtil.isNotBlank(s.get(keyList.get(i)))) {
                                    p.setMaximum(BigDecimal.valueOf(Double.valueOf(s.get(keyList.get(i)))));
                                }
                                continue;
                            case 6:
                                if (StringUtil.isNotBlank(s.get(keyList.get(i)))) {
                                    p.setMinimum(BigDecimal.valueOf(Double.valueOf(s.get(keyList.get(i)))));
                                }
                                continue;
                            case 7:
                                if (StringUtil.isNotBlank(s.get(keyList.get(i)))) {
                                    p.setSafe(BigDecimal.valueOf(Double.valueOf(s.get(keyList.get(i)))));
                                }
                                continue;
                            case 8:
                                if (StringUtil.isNotBlank(s.get(keyList.get(i)))) {
                                    if (s.get(keyList.get(i)).equals("自制")) {
                                        p.setAttribute(0);
                                    } else if (s.get(keyList.get(i)).equals("外购")) {
                                        p.setAttribute(1);
                                    }
                                }
                                continue;
                        }
                    }
                }
                if (flag == 0) {
                    if (!CollectionUtils.isEmpty(vos)) {
                        p.setOther(customFieldService.handleObjectCreateOrEdit(vos).toJSONString());
                    }
                    p.setCreateId(LoginUtil.getLoginUserId());
                    if (StringUtil.isNotBlank(p.getCode())) {
                        boolean result = productService.saveOrUpdate(p);
                        if (result) {
                            a++;
                        }
                    } else {
                        b++;
                    }
                }
            }
            userService.importLog(LoginUtil.getLoginAccount(), allDataList.size(), OwnUtil.getImportLogDataMap(dataMap, a, b, type), "product", failList);
        }
    }


    /**
     * 根据指定查询条件获取产品信息
     *
     * @param columnData  相同条件的集合
     * @param scColumnMap 自定义查询条件名和列名的映射
     * @return <条件名称,<条件值, 商品>> 的分组
     */
    public Map<String, Map<String, List<Product>>> getColumnProductsByScColumn(List<List<Map<String, Object>>> columnData, Map<String, String> scColumnMap) {
        QueryWrapper<Product> productQWr = new QueryWrapper<>();
        Map<String, Map<String, List<Product>>> columnProductsByScColumn = new HashMap<>(3);
        columnData.forEach(
                i -> {
                    if (!i.isEmpty()) {
                        productQWr.clear();
                        String searchColumn = i.get(0).get("searchColumn").toString();
                        // 获取产品数据
                        Set<String> conditionData = i.stream().map(d -> d.get(searchColumn).toString()).collect(Collectors.toSet());
                        List<Product> productList = this.list(productQWr.in(scColumnMap.get(searchColumn), conditionData));
                        switch (searchColumn) {
                            case "productCode":
                                columnProductsByScColumn.put(searchColumn, productList.stream().collect(Collectors.groupingBy(Product::getCode)));
                                break;
                            case "productName":
                                columnProductsByScColumn.put(searchColumn, productList.stream().collect(Collectors.groupingBy(Product::getName)));
                                break;
                            case "specification":
                                columnProductsByScColumn.put(searchColumn, productList.stream().collect(Collectors.groupingBy(Product::getSpecification)));
                        }
                    }
                }
        );
        return columnProductsByScColumn;

    }

    /**
     * 获取工艺路线
     *
     * @param productIds 产品ids
     */
    public List<Map<String, Object>> getProcessByProductId(Set<Integer> productIds) {
        return productMapper.getProcessByProductId(productIds);
    }

    /**
     * 根据id获取产品详情
     *
     * @param productId 产品id
     */
    public Product getDetailById(Integer productId) {
        IPage<Product> productList = this.getBaseMapper().getProductList(new Page<>(1, 1), new H5CodeVo().setProductId(productId));
        return CollectionUtils.isEmpty(productList.getRecords()) ? new Product() : productList.getRecords().get(0);
    }

    /**
     * 纠正产品库存差值
     *
     * @param difference 差值
     * @param product    产品信息
     */
    public boolean rectifyStock(BigDecimal difference, Product product) {
        if (Objects.nonNull(product) && difference.compareTo(BigDecimal.ZERO) != 0) {
            product.setStock(product.getStock().add(difference));
            return true;
        }
        return false;
    }

    /**
     * 纠正产品库存差值
     *
     * @param difference  差值
     * @param productCode 产品编码
     */
    public void rectifyStockByDifference(BigDecimal difference, String productCode) {
        Product product = this.getOne(new LambdaQueryWrapper<Product>().eq(Product::getCode, productCode).eq(Product::getDelFlag, 0));
        if (this.rectifyStock(difference, product)) {
            productService.updateById(product);
        }
    }

    /**
     * 根据删除的任务id纠正产品库存差值
     *
     * @param missionIds 需要删除的任务id
     */
    public void rectifyStockByDelMissionIds(List<Integer> missionIds) {
        if (CollectionUtils.isEmpty(missionIds)) {
            return;
        }
        Map<Integer, String> missionIdProductCodeMap = new HashMap<>(missionIds.size());
        List<Mission> missionList = missionService.list(new LambdaQueryWrapper<Mission>().eq(Mission::getLast, 0).in(Mission::getId, missionIds));
        if (!CollectionUtils.isEmpty(missionList)) {
            List<Integer> lastMissionIds = new ArrayList<>();
            missionList.forEach(i -> {
                missionIdProductCodeMap.put(i.getId(), i.getProductCode());
                lastMissionIds.add(i.getId());
            });
            List<WorkReport> workReports = workReportService.list(new LambdaQueryWrapper<WorkReport>().eq(WorkReport::getVerifyState, 1).in(WorkReport::getMissionId, lastMissionIds));
            if (!CollectionUtils.isEmpty(workReports)) {
                stockMsgService.removeStockDetailBy(workReports.stream().map(i -> i.getId().toString()).collect(Collectors.toList()));
                Map<String, BigDecimal> productCodeDifferenceMap = new HashMap<>(workReports.size());
                Set<String> productCodes = new HashSet<>();
                workReports.forEach(i -> {
                    String productCode = missionIdProductCodeMap.get(i.getMissionId());
                    BigDecimal difference = i.getGoodProductNumber().negate();
                    if (difference.compareTo(BigDecimal.ZERO) < 0) {
                        productCodeDifferenceMap.computeIfPresent(productCode, (k, v) -> v.add(difference));
                        productCodeDifferenceMap.putIfAbsent(productCode, difference);
                        productCodes.add(productCode);
                    }
                });
                if (!CollectionUtils.isEmpty(productCodes)) {
                    List<Product> productList = productService.list(new LambdaQueryWrapper<Product>().in(Product::getCode, productCodes));
                    List<Product> updateProductList = productList.stream().filter(i -> this.rectifyStock(productCodeDifferenceMap.get(i.getCode()), i)).collect(Collectors.toList());
                    if (!CollectionUtils.isEmpty(updateProductList)) {
                        productService.updateBatchById(updateProductList);
                    }
                }
            }
        }

    }

    /**
     * 获取产品库存数量
     */
    public List<Product> getProductStock() {
        return this.productMapper.getProductStock();
    }

    /**
     * 获取库存余额信息
     *
     * @param page              分页
     * @param mergeSearchResult 查询条件
     */
    public Page<Product> getStockBalancePC(Page<Product> page, StockBalanceVo mergeSearchResult) {
        Page<Product> data = this.baseMapper.getStockBalancePC(page, mergeSearchResult);
        ColumnUtils productColumnUtils = new ColumnUtils(customFieldService, ObjectType.product.getCode());
        data.getRecords().forEach(i -> i.setCustomFieldVos(productColumnUtils.getCuColumnsByJsonArray(i.getOther())));
        return data;
    }

    public List<GroupCountVo> getSecondGroupTypeCount(Integer screenPlanId, StockBalanceVo mergeSearchResult) {
        List<GroupCountVo> typeCountData = new ArrayList<>();
        if (Objects.nonNull(screenPlanId)) {
            ScreenPlan screenPlan = screenPlanService.getById(screenPlanId);
            String secondGroup = screenPlan.getSecondGroup();
            Map<String, String> cnEnMap = ColumnUtils.BASE_COLUMN_CN_EN_MAP.getOrDefault(ObjectType.product.getCode(), Collections.emptyMap());
            String enName = cnEnMap.get(secondGroup);
            if (Objects.nonNull(enName)) {
                mergeSearchResult.setSecondGroupColumnName(enName);
                typeCountData.addAll(this.getTypeCountMap(mergeSearchResult,enName));
            } else {
                mergeSearchResult.setSecondGroupColumnName(secondGroup);
                // 自定义字段分组
                CustomField customField = customFieldService.getById(secondGroup);
                if (Objects.nonNull(customFieldService.getById(secondGroup))) {
                    List<RadioOptionVo> options = JSONUtil.toList(Optional.ofNullable(customField.getCheckBox()).orElse("[]"), RadioOptionVo.class);
                    options.forEach(i -> {
                        List<Integer> productIds = customFieldService.searchCustomField(Collections.singletonMap(customField.getId(), i.getValue()), ObjectType.product.getCode());
                        mergeSearchResult.setIds(productIds);
                        long total = this.baseMapper.getGroupCountVo(mergeSearchResult);
                        typeCountData.add(new GroupCountVo().setOptionNum(total).setOptionName(i.getValue()).setOptionValue(i.getValue()).setTypeName(customField.getChineseName()));
                    });
                }
            }
        }
        return typeCountData;

    }

    private Collection<? extends GroupCountVo> getTypeCountMap(StockBalanceVo searchCondition, String groupColumn) {
        Map<String, String> typeValueNameMap = new HashMap<>(10);
        List<String> typeChineseName = new ArrayList<>(1);
        switch (groupColumn) {
            case "attribute":
                typeChineseName.add("产品属性");
                typeValueNameMap.put("0", "自制");
                typeValueNameMap.put("1", "外购");
                typeValueNameMap.put("2", "委外");
                searchCondition.setAttribute(null);
                break;
        }
        List<GroupCountVo> typeCountData = this.baseMapper.getTypeCountMap(searchCondition, groupColumn);
        typeCountData.forEach(i -> {
            i.setTypeName(typeChineseName.get(0)).setOptionName(typeValueNameMap.get(i.getOptionValue()));
            typeValueNameMap.remove(i.getOptionValue());
        });
        typeValueNameMap.forEach((k, v) -> {
            typeCountData.add(new GroupCountVo().setOptionNum(0L).setTypeName(typeChineseName.get(0)).setOptionName(v).setOptionValue(k));
        });

        return typeCountData.stream().sorted(Comparator.comparingInt(f -> Integer.parseInt(f.getOptionValue()))).collect(Collectors.toList());
    }
}
